/**
 * 
 */
package edu.pw.treegrid.server.reportmodel;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import xalan.xml.XMLUtils;
import edu.pw.treegrid.server.classmodel.DomainAttribute;
import edu.pw.treegrid.server.classmodel.DomainClass;
import edu.pw.treegrid.server.classmodel.SimpleAttribute;
import edu.pw.treegrid.server.query.Node;
import edu.pw.treegrid.server.service.XMLMarshaller;

/** 
 * @author Piotrek
 */
public abstract class ReportColumn {
	private static Logger log = Logger.getLogger("xalan.reports");
	
	public static final String COLUMN_ELEMENT = "column";
	public static final String DOMAIN_ATTRIBUTE_ELEMENT = "domainAttribute";
	public static final String REF_ATTRIBUTE = "ref";
	public static final String NAME_ELEMENT = "name";

	public ReportColumn(String name) {
		this.name = name;
	}
	
	private DomainAttribute domainAttribute;

	public DomainAttribute getDomainAttribute() {
		return domainAttribute;
	}

	public void setDomainAttribute(DomainAttribute domainAttribute) {
		this.domainAttribute = domainAttribute;
	}

	public abstract Node buildQueryNode();

	public abstract SimpleAttribute getSimpleAttribute();
	
	private String name = "";

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ReportColumn other = (ReportColumn) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "ReportColumn " + name;
	}

	public Element serializeToXML(Document document) {
		Element columnElement = document.createElement(COLUMN_ELEMENT);
		columnElement.setAttribute(NAME_ELEMENT, this.name);

		Element domainAttributeElement = document.createElement(DOMAIN_ATTRIBUTE_ELEMENT);
		if(this.domainAttribute != null) {
			domainAttributeElement.setAttribute(REF_ATTRIBUTE, this.domainAttribute.getId());
		}
		columnElement.appendChild(domainAttributeElement);
		
		this.serializeToXML(document, columnElement);
		
		return columnElement;
	}

	protected abstract void serializeToXML(Document document, Element columnElement);
	
	protected abstract boolean isSerialize();

	public static ReportColumn newColumn(Element ae, XMLMarshaller marshaller) {
		ReportColumn rc = null;
		
		if(isExpressionColumn(ae)) {
			rc = new ExpressionColumn("");
		}
		else if(isSecondDimensionColumn(ae)){
			rc = new SecondDimensionColumn("");
		}
		else if(isReferenceColumn(ae)) {
			rc = new ReportReferenceColumn("");
		}
		else if(isSimpleColumn(ae)) {
			rc = new ReportSimpleColumn("");
		}
		
		rc.deserializeFromXML(ae, marshaller);
		
		return rc;
	}

	protected void deserializeFromXML(Element e, XMLMarshaller marshaller) {
		String attrId = XMLUtils.getChildElementAttribute(e, DOMAIN_ATTRIBUTE_ELEMENT, REF_ATTRIBUTE);
		this.domainAttribute = marshaller.getAttributeById(attrId);
		this.name = XMLUtils.getAttributeText(e, NAME_ELEMENT);
		if(domainAttribute == null) {
			String reportName = this.getReport() != null ? this.getReport().getName() : "null";
			log.warn("Atrybut [" + attrId + "] dla kolumny [" + this.name + "] nie istnieje w raporcie [" + reportName + "].");
		}
		
		if(this.getReport() != null) {
			DomainClass rc = this.getReport().getMainClass();
			DomainClass ac = domainAttribute.getDomainClass();
			if(rc!=null && !rc.equals(ac)) {
				log.warn("Atrybut [" + attrId + "] w kolumnie [" + this.name + "] pochodzi z klasy [" + ac.getName() + "] a klasa raportu to [" + rc.getName() + "]");
			}
		}
	}
	
	private static boolean isExpressionColumn(Element ae) {
		return  ae.getElementsByTagName(ExpressionColumn.EXPRESSION_ELEMENT).getLength() > 0;
	}
	
	private static boolean isSecondDimensionColumn(Element ae){
		return "true".equals(ae.getAttribute(SecondDimensionColumn.SECOND_DIMENSION_ATTR));
	}
	
	private static boolean isSimpleColumn(Element ae) {
		return !isReferenceColumn(ae);
	}

	private static boolean isReferenceColumn(Element ae) {
		return ae.getElementsByTagName(ReportColumn.COLUMN_ELEMENT).getLength() > 0;
	}
	
	private Report report;

	public Report getReport() {
		return report;
	}

	public void setReport(Report report) {
		this.report = report;
	}

	public abstract String getImageSrc();
	
	public abstract ReportSimpleColumn getReportSimpleColumn();
}